#include "logger/logger.h"
#include "utils/utils/string_util.h"
#include <mutex>
#include <stdarg.h>

namespace
{
logger::MessageOutput gMessageOutput;

std::mutex gMutex;

std::string formatStr(const char *fmt, va_list args)
{
    va_list arg_copy;
    va_copy(arg_copy, args);

    auto size_buf = vsnprintf(nullptr, 0, fmt, args) + 1;
    std::unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);

    if (!buf)
        return "";

    vsnprintf(buf.get(), size_buf, fmt, arg_copy);
    va_end(arg_copy);
    return std::string(buf.get(), buf.get() + size_buf - 1);
}
}

namespace logger
{
void installMessageHandler(MessageOutput messageOutput)
{
    gMessageOutput = messageOutput;
}
void debugLog(const MessageLogContext &context, const char *fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    auto str = formatStr(fmt, arg_list);
    va_end(arg_list);

    if (gMessageOutput)
    {
        std::lock_guard lock_guard(gMutex);
        gMessageOutput(LEVEL_DEBUG, context, str);
    }
    else
    {
        printf("%s\n", str.c_str());
    }
}
void infoLog(const MessageLogContext &context, const char *fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    auto str = formatStr(fmt, arg_list);
    va_end(arg_list);

    if (gMessageOutput)
    {
        std::lock_guard lock_guard(gMutex);
        gMessageOutput(LEVEL_INFO, context, str);
    }
    else
    {
        printf("%s\n", str.c_str());
    }
}
void warningLog(const MessageLogContext &context, const char *fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    auto str = formatStr(fmt, arg_list);

    if (gMessageOutput)
    {

        std::lock_guard lock_guard(gMutex);
        gMessageOutput(LEVEL_WARNING, context, str);
    }
    else
    {
        printf("%s\n", str.c_str());
    }
}
void errorLog(const MessageLogContext &context, const char *fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    auto str = formatStr(fmt, arg_list);
    va_end(arg_list);

    if (gMessageOutput)
    {
        std::lock_guard lock_guard(gMutex);
        gMessageOutput(LEVEL_ERROR, context, str);
    }
    else
    {
        fprintf(stderr, "%s\n", str.c_str());
    }
}
void fatalLog(const MessageLogContext &context, const char *fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    auto str = formatStr(fmt, arg_list);
    va_end(arg_list);

    if (gMessageOutput)
    {
        std::lock_guard lock_guard(gMutex);
        gMessageOutput(LEVEL_FATAL, context, str);
    }
    else
    {
        fprintf(stderr, "%s\n", str.c_str());
    }
}

}


